package com.leyou.item.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.pojo.PageResult;
import com.leyou.common.utils.BeanHelper;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.entity.Category;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SkuMapper;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
public class GoodsService extends ServiceImpl<SkuMapper, Sku> {

    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private SpuDetailMapper detailMapper;

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    public PageResult<SpuDTO> goodsPageQuery(Integer page, Integer rows, String key, Boolean saleable) {
        //创建分页对象
        IPage<Spu> iPage = new Page<>(page, rows);
        //创建封装条件的对象
        QueryWrapper<Spu> wrapper = Wrappers.query();
        //判断是否有查询条件
        if(StringUtils.isNotBlank(key)){
            wrapper.like("name", key);
        }
        //判断是否有上下架条件，mysql中使用tinyint作为布尔值，只要非0就表示true，反之就是false。
        //java中只要是true存入tinyint自动转成1，false自动转成0
        if(saleable!=null){
            wrapper.eq("saleable", saleable);
        }
        //执行分页条件查询
        iPage = spuMapper.selectPage(iPage, wrapper);
        //先获取数据列表
        List<Spu> spus = iPage.getRecords();
        if(CollectionUtils.isEmpty(spus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        //将Spu集合转成SpuDTO集合
        List<SpuDTO> spuDTOS = BeanHelper.copyWithCollection(spus, SpuDTO.class);
        //对SpuDTO集合中每个对象的分类名称和品牌名称赋值
        handlerCategoryNameAndBrandName(spuDTOS);
        //创建自定义的分页对象
        PageResult<SpuDTO> pageResult = new PageResult<>(
                iPage.getTotal(),
                iPage.getPages(),
                spuDTOS
        );
        return pageResult;
    }

    private void handlerCategoryNameAndBrandName(List<SpuDTO> spuDTOS) {
        //遍历
        spuDTOS.forEach(spuDTO -> {
            //根据品牌id查询品牌名称
            String brandName = brandService.findBrandById(spuDTO.getBrandId()).getName();
            //将品牌名称赋值给SpuDTO对象
            spuDTO.setBrandName(brandName);

            //根据分类id的集合查询出分类名称的拼接
            String categoriesNames = categoryService.findCategoriesByIds(spuDTO.getCategoryIds())//得到分类对象的集合
                    .stream()//转流，其实就是遍历，其中临时变量就是每一个分类对象
                    .map(Category::getName)//每一个分类对象，都采用类名的引用，去获取自身对象中name值
                    .collect(Collectors.joining("|"));//将所有name值以 | 隔开，成为字符串
            //将分类的名称的拼接赋值给SpuDTO对象
            spuDTO.setCategoryName(categoriesNames);
        });
    }

    public void saveGoods(SpuDTO spuDTO) {
        try {
            //将SpuDTO对象转成Spu对象
            Spu spu = BeanHelper.copyProperties(spuDTO, Spu.class);
            //设置新添加的商品为下架的状态
            spu.setSaleable(false);
            //添加Spu
            spuMapper.insert(spu);

            //获取Spu的id
            Long spuId = spu.getId();

            //从souDTO中获取SpuDetail
            SpuDetail spuDetail = spuDTO.getSpuDetail();
            //给SpuDetail的主键赋值
            spuDetail.setSpuId(spuId);
            //添加SpuDetail
            detailMapper.insert(spuDetail);

            //从spuDTO中获取Sku的集合
            List<Sku> skus = spuDTO.getSkus();
            //对Sku集合中每个Sku的SpuId赋值
            skus.forEach(sku -> {
                sku.setSpuId(spuId);
            });
            //批量添加skus
            saveBatch(skus);
        }catch (Exception e){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

    }

    public void updateSaleable(Long id, Boolean saleable) {
        try {
            //商品上下架
            Spu entity = new Spu();
            entity.setId(id);
            entity.setSaleable(saleable);
            spuMapper.updateById(entity);
            //索引库和静态化页面的数据同步
            //第一：feign来实现【同步】。第二：MQ来实现【异步】。
            String routingKey = saleable ? MQConstants.RoutingKey.ITEM_UP_KEY : MQConstants.RoutingKey.ITEM_DOWN_KEY;
            amqpTemplate.convertAndSend(MQConstants.Exchange.ITEM_EXCHANGE_NAME, routingKey, id);
        }catch (Exception e){
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }

    }

    public List<Sku> findSkusBySpuId(Long id) {
        Sku entity = new Sku();
        entity.setSpuId(id);
        QueryWrapper<Sku> wrapper = Wrappers.query(entity);
        List<Sku> skus = skuMapper.selectList(wrapper);
        if(CollectionUtils.isEmpty(skus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return skus;
    }

    public SpuDetail findSpuDetailById(Long id) {
        SpuDetail spuDetail = detailMapper.selectById(id);
        if(spuDetail==null){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return spuDetail;
    }

    public SpuDTO findSpuDTOById(Long id) {
        //根据id查询SpuDTO
        Spu spu = spuMapper.selectById(id);
        if(spu==null){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        SpuDTO spuDTO = BeanHelper.copyProperties(spu, SpuDTO.class);

        //根据spuId查询Sku集合
        List<Sku> skus = findSkusBySpuId(id);
        spuDTO.setSkus(skus);

        //根据id查询SpuDetail对象
        SpuDetail spuDetail = findSpuDetailById(id);
        spuDTO.setSpuDetail(spuDetail);

        return spuDTO;
    }

    public List<Sku> findSkusByIds(List<Long> ids) {
        List<Sku> skus = skuMapper.selectBatchIds(ids);
        if(CollectionUtils.isEmpty(skus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return skus;
    }


    public void minusStock(Map<Long, Integer> params) {
        try {
            params.entrySet().forEach(entry->{
                //根据id查询出当前sku对象
                Sku sku = skuMapper.selectById(entry.getKey());

                Sku entity = new Sku();
                entity.setId(entry.getKey());
                entity.setStock(sku.getStock()-entry.getValue());
                skuMapper.updateById(entity);
            });
        }catch (Exception e){
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }
    }

    //还库存
    public void addStock(Map<Long, Integer> params) {
        try {
            params.entrySet().forEach(entry->{
                //根据id查询出当前sku对象
                Sku sku = skuMapper.selectById(entry.getKey());

                Sku entity = new Sku();
                entity.setId(entry.getKey());
                entity.setStock(sku.getStock()+entry.getValue());
                skuMapper.updateById(entity);
            });
        }catch (Exception e){
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }

    }

    //查库存
    public void queryStock(Map<Long, Integer> params){
        try {
            params.entrySet().forEach(entry->{
                //根据id查询出当前sku对象
                Sku sku = skuMapper.selectById(entry.getKey());
                if (sku.getStock() < entry.getValue()){
                    throw new LyException(ExceptionEnum.STOCK_NOT_ENOUGH_ERROR);
                }
            });
        }catch (Exception e){
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }
    }
}
